/*------------------------------------------------------------------------------
 * PROJ : PrototypeWithSpring
 * NAME : sculove.spring.framework.util.RequestToken.java
 *        
 * Copyright 2009 sculove All rights reserved
 *------------------------------------------------------------------------------
 */
package sculove.spring.framework.util;

import java.security.MessageDigest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.multipart.MultipartHttpServletRequest;

/**
 * <pre>
 * sculove.spring.framework.util.RequestToken.java
 * 
 * 중복호출을 막는 Request Token 객체
 * 
 * </pre>
 * 
 * @date : 2009. 10. 10. 오후 4:51:13
 * @version :
 * @author : sculove
 */
public class RequestToken {
	
	/**
     * request와 session에 request token을 설정한다.
     * @param req
     * @return
     */
    public static String setToken(HttpServletRequest req) {
		HttpSession session = req.getSession();

		long systime = System.currentTimeMillis();
		byte[] time = new Long(systime).toString().getBytes();
		byte[] id = session.getId().getBytes();
		String token = "";

		try {
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			md5.update(id);
			md5.update(time);

			token = toHex(md5.digest());
			req.setAttribute(Configuration.getPropInstance().getString("com.requestToken"), token);
			SessionUtil.set(req, Configuration.getPropInstance().getString("com.requestToken"), token);
		} catch (Exception e) {   
		    Log log = LogFactory.getLog("RequestToken");
		    log.error("Unable to calculate MD5 Diguests", e);
		}
		return token;
	}

	/**
	 * 세션의 reqeust token값을 초기화한다.
	 * @param req
	 */
	private static void resetToken(HttpServletRequest req) {
		HttpSession session = req.getSession(false);
		
		if (session == null) {
			return;
		}
		session.removeAttribute(Configuration.getPropInstance().getString("com.requestToken"));
	}

	/**
	 * Request Token 유효성 검증
	 * @param req
	 * @return
	 */
	public static boolean isValid(HttpServletRequest req) {
		HttpSession session = req.getSession(false);
		Log logger = LogFactory.getLog("TEST");
		if (session == null) {
			return false;
		}
		String sessionToken = (String)session.getAttribute(Configuration.getPropInstance().getString("com.requestToken"));
		
		String requestToken = null;

		/* Multi-part request 인 경우
		 * spring의 MultipartHttpServletRequest를 이용하여 파라미터를 얻음.
		 *
		 * MultipartHttpServletRequest는 어떻게 얻나? 
		 * 
		 * org.springframework.web.servlet.DispatcherServlet.initMultipartResolver에서 
		 * MultipartResolver객체가 초기화된 이후,
		 * DispatcherServlet의 checkMultipart를 통해 MultipartHttpServletRequest를  얻을수 있다.
		 */
		if(req instanceof MultipartHttpServletRequest) {
			MultipartHttpServletRequest mpRequest = (MultipartHttpServletRequest)req;
			requestToken = mpRequest.getParameter(Configuration.getPropInstance().getString("com.requestToken"));
		} else {
			requestToken = req.getParameter(Configuration.getPropInstance().getString("com.requestToken"));
		}
		logger.info("[session] " + sessionToken + " , [requestToken] " + requestToken);
		resetToken(req);
		
		if (requestToken == null || sessionToken == null) {
			return false;
		} else {
			return requestToken.equals(sessionToken);
		}
	}
	
	private static String toHex(byte[] digest) {
		StringBuffer buf = new StringBuffer();
		for (int i = 0; i < digest.length; i++) {
			buf.append(Integer.toHexString((int) digest[i] & 0x00ff));
		}
		return buf.toString();
	}
}